// 
//  Copyright © 2009 Jiří Zárevúcky <zarevucky.jiri@gmail.com>
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as
//  published by the Free Software Foundation, either version 3 of the
//  License, or (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Affero General Public License for more details.
// 
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// 


using System;
using System.Collections.Generic;

using Galaxium.Protocol.Xmpp.Library.Xml;

// TODO: better handling of namespaces

namespace Galaxium.Protocol.Xmpp.Library.Core
{
	public class StanzaEventArgs: EventArgs
	{
		public Stanza Stanza { get; private set; }
		public StanzaEventArgs (Stanza stanza) { Stanza = stanza; }
	}
	
	public abstract class Stanza: Element
	{
		private Stanza ()
			:base ()
		{
		}
		
		public Stanza (string name)
			:base (name)
		{
		}
		
		protected Stanza (Element elm)
			:base (elm.Clone ())
		{
		}

		#region Properties

		public JabberID To {
			get {
				string to = GetAttribute ("to");
				return (to == null) ? null : new JabberID (to);
			}
			set { SetAttribute ("to", value); }
		}
		
		public JabberID From {
			get {
				string from = GetAttribute ("from");
				return (from == null) ? null : new JabberID (from);
			}
			set { SetAttribute ("from", value); }
		}
		
		public string ID {
			get { return GetAttribute ("id"); }
			set { SetAttribute ("id", value); }
		}
		
		public string Type {
			get { return GetAttribute ("type"); }
			set { SetAttribute ("type", value); }
		}
		
		public string Lang {
			get { return GetAttribute ("xml:lang"); }
			set { SetAttribute ("xml:lang", value); }
		}

		public StanzaError Error {
			get {
				var error = FirstChild ("error", null);
				return error == null ? null : new StanzaError (error);
				// FIXME: !!!!!!
			}
		}
		
		public void AppendError (StanzaError error)
		{
			if (error == null)
				throw new ArgumentNullException ("error");
			
			AppendChild (error);
		}

		public bool IsError {
			get { return Type == "error"; }
		}

		#endregion
		
		public Stanza CreateErrorResponse (string condition)
		{
			return CreateErrorResponse (condition, null);
		}
		
		public Stanza CreateErrorResponse (string condition, string description)
		{
			if (IsError)
				throw new InvalidOperationException ("Trying to respond to an error with another error.");
			Stanza err = (Stanza) Clone ();
			err.From = null;
			err.To = From;
			err.Type = "error";
			err.AppendError (new StanzaError (condition, description));
			return err;
		}
	}
}
